This example mirrors ui.html.

In [1]:
from pathlib import Path

from ipyniivue import download_dataset

BASE_API_URL = "https://niivue.com/demos/images/"
DATA_FOLDER = Path("images")

# Download data for example
download_dataset(
    BASE_API_URL,
    DATA_FOLDER,
    files=[
        "mni152.nii.gz",
        "hippo.nii.gz",
    ],
)
mni152.nii.gz already exists.
hippo.nii.gz already exists.
Dataset downloaded successfully to images.
In [2]:
import ipywidgets as widgets
from IPython.display import display

from ipyniivue import DragMode, NiiVue, ShowRender, SliceType

# output widget for showing header
out = widgets.Output()

# initialize niivue
nv = NiiVue(
    height=500,
    is_colorbar=True,
    is_radiological_convention=False,
    show_3d_crosshair=True,
    drag_and_drop_enabled=True,
    is_slice_mm=True,
    multiplanar_show_render=ShowRender.ALWAYS,
    slice_type=SliceType.MULTIPLANAR,
)

nv.graph.auto_size_multiplanar = True
nv.graph.opacity = 1.0
nv.set_clip_plane(0.3, 270, 0)
nv.set_render_azimuth_elevation(120, 10)

# Load initial volume
nv.load_volumes([{"path": DATA_FOLDER / "mni152.nii.gz"}])


# event handlers


def on_file_change(change):
    """Handle file change."""
    action = change["new"]
    if not action:
        return

    if action == "Screen Shot":
        nv.save_scene("ScreenShot.png")
    elif action == "Show Header":
        with out:
            out.clear_output()
            if nv.volumes:
                print(nv.volumes[0].hdr)
            else:
                print("No volume loaded.")

    file_dropdown.value = None


def on_view_change(change):
    """Handle view change."""
    action = change["new"]
    if not action:
        return

    if action == "Axial":
        nv.set_slice_type(SliceType.AXIAL)
    elif action == "Sagittal":
        nv.set_slice_type(SliceType.SAGITTAL)
    elif action == "Coronal":
        nv.set_slice_type(SliceType.CORONAL)
    elif action == "Render":
        nv.set_slice_type(SliceType.RENDER)
    elif action == "A+C+S":
        nv.opts.multiplanar_show_render = ShowRender.NEVER
        nv.set_slice_type(SliceType.MULTIPLANAR)
    elif action == "A+C+S+R":
        nv.opts.multiplanar_show_render = ShowRender.ALWAYS
        nv.set_slice_type(SliceType.MULTIPLANAR)
    elif action == "Colorbar":
        nv.opts.is_colorbar = not nv.opts.is_colorbar
    elif action == "Radiological":
        nv.opts.is_radiological_convention = not nv.opts.is_radiological_convention
    elif action == "Render Crosshair":
        nv.opts.show_3d_crosshair = not nv.opts.show_3d_crosshair
    elif action == "Render Clip Plane":
        current_depth = nv.scene.clip_plane_depth_azi_elevs[0][0]
        new_depth = 0.3 if current_depth > 1 else 2
        nv.set_clip_plane(new_depth, 270, 0)

    view_dropdown.value = None


def on_color_change(change):
    """Handle color change."""
    action = change["new"]
    if not action:
        return

    if action == "Dark Background":
        if nv.opts.back_color[0] < 0.5:
            nv.opts.back_color = (1.0, 1.0, 1.0, 1.0)
        else:
            nv.opts.back_color = (0.0, 0.0, 0.0, 1.0)
        nv.draw_scene()
    elif nv.volumes:
        nv.volumes[0].colormap = action.lower()
        nv.update_gl_volume()

    color_dropdown.value = None


def on_drag_change(change):
    """Handle drag change."""
    action = change["new"]
    if not action:
        return

    if action == "Contrast":
        nv.opts.drag_mode = DragMode.CONTRAST
    elif action == "Measurement":
        nv.opts.drag_mode = DragMode.MEASUREMENT
    elif action == "Pan":
        nv.opts.drag_mode = DragMode.PAN
    elif action == "None":
        nv.opts.drag_mode = DragMode.NONE

    drag_dropdown.value = None


def on_script_change(change):
    """Handle script change."""
    action = change["new"]
    if not action:
        return

    if action == "mesh":
        nv.load_volumes([{"path": DATA_FOLDER / "mni152.nii.gz"}])
        nv.load_meshes(
            [
                {
                    "path": DATA_FOLDER / "BrainMesh_ICBM152.lh.mz3",
                    "rgba255": [200, 162, 255, 255],
                },
                {"path": DATA_FOLDER / "dpsv.trx", "rgba255": [255, 255, 255, 255]},
            ]
        )
    else:
        nv.meshes = []
        filename = f"{action}.nii.gz"
        nv.load_volumes([{"path": DATA_FOLDER / filename}])

    script_dropdown.value = None


# location string
intensity_label = widgets.Label(value="")


def handle_location_change(data):
    """Handle location change."""
    if "string" in data:
        intensity_label.value = data["string"]


nv.on_location_change(handle_location_change)


# ui

file_dropdown = widgets.Dropdown(
    options=["Screen Shot", "Show Header"], description="File:", value=None
)
file_dropdown.observe(on_file_change, names="value")

view_dropdown = widgets.Dropdown(
    options=[
        "Axial",
        "Sagittal",
        "Coronal",
        "Render",
        "A+C+S",
        "A+C+S+R",
        "Colorbar",
        "Radiological",
        "Render Crosshair",
        "Render Clip Plane",
    ],
    description="View:",
    value=None,
)
view_dropdown.observe(on_view_change, names="value")

color_dropdown = widgets.Dropdown(
    options=["Gray", "Plasma", "Viridis", "Inferno", "Dark Background"],
    description="Color:",
    value=None,
)
color_dropdown.observe(on_color_change, names="value")

drag_dropdown = widgets.Dropdown(
    options=["Contrast", "Measurement", "Pan", "None"], description="Drag:", value=None
)
drag_dropdown.observe(on_drag_change, names="value")

script_dropdown = widgets.Dropdown(
    options=["FLAIR", "mni152", "shear", "ct_perfusion", "pcasl", "mesh"],
    description="Script:",
    value=None,
)
script_dropdown.observe(on_script_change, names="value")

# display all

menu_bar1 = widgets.HBox([file_dropdown, view_dropdown, color_dropdown])
menu_bar2 = widgets.HBox([drag_dropdown, script_dropdown])
app_layout = widgets.VBox([menu_bar1, menu_bar2, nv, intensity_label, out])

display(app_layout)